//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using Eas;
using Eas.WebCrawler.Interfaces;

namespace Eas.WebCrawler.Interfaces {

    /// <summary>Trace argument that wraps a <see cref="ProcessingState"/>.</summary>
    public class ProcessingStateEventArgs : System.EventArgs {
        /// <summary>Constructs a <see cref="ProcessingStateEventArgs"/> from a <see cref="ProcessingState"/>.</summary>
        /// <param name="state">The <see cref="ProcessingState"/> to be wrapped by this class.</param>
        public ProcessingStateEventArgs(ProcessingState state) {
            _State = state;
        }

        /// <summary>The <see cref="ProcessingState"/> that is processing the current request.</summary>
        /// <remarks>Backing field for the ProcessingState property.</remarks>
        /// <seealso cref="State"/>
        private ProcessingState _State;

        /// <summary>The ProcessingState that is processing the current request.</summary>
        public ProcessingState State {
            get { return _State; }
        }

        /// <summary>Returns whether the passed in <see cref="object"/> is a <see cref="ProcessingStateEventArgs"/> that is equal to this instance.</summary>
        /// <param name="obj">The <see cref="object"/> to compare.</param>
        /// <returns><code>true</code> id the two objects are equal, otherwise <code>false</code>.</returns>
        public override bool Equals(object obj) {
            ProcessingStateEventArgs other = obj as ProcessingStateEventArgs;
            if (other == null)
                return false;
            return other.State.Id.Equals(this.State.Id);
        }

        /// <summary>Returns the hash of this object.</summary>
        /// <returns>The hash of this object.</returns>
        public override int GetHashCode() {
            return State.Id;
        }
    }

    /// <summary>Wraps a <see cref="ProcessingState"/> and a <see cref="String"/> message.</summary>
    public class ProcessingStateMessageEventArgs : ProcessingStateEventArgs {
        /// <summary>Constructs a <see cref="ProcessingStateMessageEventArgs"/>.</summary>
        /// <param name="state">The <see cref="ProcessingState"/> which generated this event.</param>
        /// <param name="message">The message of the event.</param>
        public ProcessingStateMessageEventArgs(ProcessingState state, string message) : base(state) {
            _Message = message;
        }

        /// <summary>A text description of the event.</summary>
        /// <remarks>Backing field for the Message property.</remarks>
        /// <seealso cref="Message"/>
        private string _Message;

        /// <summary>A text description of the event.</summary>
        public string Message {
            get { return _Message; }
        }

        /// <summary>Compares an incoming object with this one.</summary>
        /// <param name="obj">The object to compare.</param>
        /// <returns><code>true</code> if the two objects are equal, otherwise <code>false</code>.</returns>
        public override bool Equals(object obj) {
            ProcessingStateMessageEventArgs other = obj as ProcessingStateMessageEventArgs;
            if (other == null)
                return false;
            return other.Message.Equals(this.Message);
        }

        /// <summary>Returns the hash of this object.</summary>
        /// <returns>The hash of this object.</returns>
        public override int GetHashCode() {
            return Message.GetHashCode();
        }
    }


    /// <summary>An <see cref="EventArgs "/> which is fired if a Url could not be processed.</summary>
    public class UrlFailedEventArgs : ProcessingStateEventArgs {

        /// <summary>Constructs a <see cref="UrlFailedEventArgs"/>.</summary>
        /// <param name="state">The <see cref="ProcessingState"/> for processing the failed url.</param>
        /// <param name="resultDescription">A description of the reason for the failures.</param>
        /// <param name="resultCode">The http response code generated by this failure, or <code>500</code> if the response code could not be determined.</param>
        public UrlFailedEventArgs(ProcessingState state, string resultDescription, int resultCode) : base(state) {
            _ResultCode = resultCode;
            _ResultDescription = resultDescription;
        }

        /// <summary>The resultCode of the failure</summary>
        /// <remarks>Backing field for the ResultCode property.</remarks>
        /// <seealso cref="ResultCode"/>
        private int _ResultCode;

        /// <summary>A text description of the failure.</summary>
        /// <remarks>Backing field for the ResultDescription property.</remarks>
        /// <seealso cref="ResultDescription"/>
        private string _ResultDescription;

        /// <summary>A text description of the failure.</summary>
        public string ResultDescription {
            get { return _ResultDescription; }
        }

        /// <summary>The resultCode of the failure</summary>
        public int ResultCode {
            get { return _ResultCode; }
        }

        /// <summary>Compares the passes in object to this one for equality.</summary>
        /// <param name="obj">The object to compare.</param>
        /// <returns><code>true</code> if the two objects are equal, otherwise <code>false</code>.</returns>
        public override bool Equals(object obj) {
            UrlFailedEventArgs other = obj as UrlFailedEventArgs;
            if(other==null) return false;

            return this.State.Request.Uri.Equals(other.State.Request.Uri); 
        }

        /// <summary>Returns the hash of this object.</summary>
        /// <returns>The hash of this object.</returns>
        public override int GetHashCode() {
            return this.State.Request.Uri.GetHashCode();
        }
    }

    /// <summary>An <see cref="EventArgs"/> that is used when firing events to notify recipients that a Url was processed succesfully.</summary>
    public class UrlCompletedEventArgs : ProcessingStateEventArgs {

        /// <summary>The <see cref="TemporaryStorage"/> from which one can extract the contents of retrieving the processed url.</summary>
        /// <remarks>Backing field for the Storage property.</remarks>
        /// <seealso cref="Storage"/>
        private TemporaryStorage _Storage;

        /// <summary>Constructs this event arg out of a bool and an instance of a <see cref="Eas.WebCrawler.Interfaces.TemporaryStorage"/></summary>
        /// <param name="storage">The storage from which the body of the url can be extracted.</param>
        /// <param name="state">The state created by processing the current request.</param>
        public UrlCompletedEventArgs(ProcessingState state, TemporaryStorage storage) :base(state){
            _Storage = storage;
        }

        /// <summary>The <see cref="TemporaryStorage"/> from which one can extract the contents of retrieving the processed url.</summary>
        public TemporaryStorage Storage {
            get { return _Storage; }
        }

        /// <summary>Compares the passed-in object to this one for equality.</summary>
        /// <param name="obj">The object to compare.</param>
        /// <returns><code>true</code> if the two objects are equal, otherwise <code>false</code>.</returns>
        public override bool Equals(object obj) {
            UrlCompletedEventArgs other = obj as UrlCompletedEventArgs;
            if (other == null)
                return false;
            return this.State.Request.Uri == other.State.Request.Uri;
        }

        /// <summary>Returns the has of this object.</summary>
        /// <returns>The hash of this object.</returns>
        public override int GetHashCode() {
            return this.State.Request.Uri.GetHashCode();
        }
    }

    /// <summary>Contains the collection of events fired while crawling.</summary>
    public interface WebCrawlerEvents {
        /// <summary>Fired just before any workers begin crawling.</summary>
        event EventHandler Starting;
        /// <summary>Fired after all workers have stopped crawling.</summary>
        /// <remarks>This event can be fired because someone called <see cref="WebCrawlerEngine.Stop"/> on the crawler, or because all requests completed processing.</remarks>
        event EventHandler Stopped;
        /// <summary>Fired after all workers have completed pausing.</summary>
        event EventHandler Paused;
        /// <summary>Fired just before any workers have begun to pause.</summary>
        event EventHandler Unpausing;
        /// <summary>Fired after a worker has acquired a request to be processed.</summary>
        event EventHandler<ProcessingStateEventArgs> UrlBeganProcessing;
        /// <summary>Fired after a request has been succesfully downloaded.</summary>
        event EventHandler<UrlCompletedEventArgs> UrlProcessed;
        /// <summary>Fired with any relevant traces messages.</summary>
        /// <remarks>Trace events are only fired if the <see cref="TraceLevel"/> of the trace is as high as the <see cref="TraceLevel"/> set on this <see cref="WebCrawlerEvents"/>.</remarks>
        event EventHandler<ProcessingStateMessageEventArgs> OnTrace;
        /// <summary>Fired when an error occurs.</summary>
        event EventHandler<ProcessingStateMessageEventArgs> OnError;
        /// <summary>Fired when a request failed.</summary>
        event EventHandler<UrlFailedEventArgs> UrlFailed;
        /// <summary>Specifies how critical a trace must be in order to for it to generate an <see cref="OnTrace"/> event.</summary>
        TraceLevel TraceLevel { get; set;}
    }
}
